<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>绘制图形和文字</title>
</head>

<body>
  <canvas id="canvas" height="400" width="400"></canvas>
</body>
<script>
  var canvas = document.getElementById('canvas'); //获取canvas标签
  var ctx = canvas.getContext('2d'); //获取上下文
  canvas.style.border = '2px solid #000';

  //定义饼状图数据
  var data = [{
    'value': 0.1,
    'color': '#FFFF00',
    'title': 'A'
  },
  {
    'value': 0.2,
    'color': '#00FF00',
    'title': 'B'
  },
  {
    'value': 0.3,
    'color': 'red',
    'title': 'C'
  },
  {
    'value': 0.4,
    'color': 'blue',
    'title': 'D'
  },
  ]

  //绘制饼状图
  var tempAngle = -90; //记录绘制到了哪个角度
  for (var i = 0; i < data.length; i++) {
    ctx.beginPath(); //每一次循环都绘制不同的扇区，所以都要开启新状态
    ctx.moveTo(200, 200); //每一次都回到圆心点开始绘制
    var angle = data[i].value * 360; //每一个扇区的角度
    ctx.fillStyle = data[i].color; //颜色填充按照数据遍历
    var startAngle = tempAngle * Math.PI / 180; //起始角度
    var endAngle = (tempAngle + angle) * Math.PI / 180; //每一次的结束角度=起始角度+扇区角度
    ctx.arc(200, 200, 100, startAngle, endAngle);

    //绘制文字
    var txt = data[i].value * 100 + '%'; //获取要绘制的文字
    var x, y; //文字坐标
    var txtAngle = tempAngle + 1 / 2 * angle; //文字位置的角度 = 起始角度 + 扇区的一半
    //计算文字坐标
    x = 200 + Math.cos(txtAngle * Math.PI / 180) * (100 + 20);
    y = 200 + Math.sin(txtAngle * Math.PI / 180) * (100 + 20);

    ctx.font = '20px "微软雅黑"'; //设置字体
    if (txtAngle > 90 && txtAngle < 270) { //设置y轴左边的文字结束位置对齐，防止文字显示不全
      ctx.textAlign = 'end';
    }

    ctx.fillText(txt, x, y); //填充文字

    ctx.fill();
    tempAngle = tempAngle + angle; //每次绘制完一次扇区起始角度为原角度加该扇区角度
  }
</script>

</html>